
/* usbn960x.c
* Copyright (C) 2005  Benedikt Sauter
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include "usbn2mc.h"
#include "uart.h"

//*******************************************************************
// add own vendor requests          
// ********************************************************************

// decode your own vendor requests

void USBNDecodeVendorRequest (DeviceRequest * req)
{
#if 0
	//SendHex(req->bRequest);       // decode request code
	SendHex (req->wLength);		// decode request code
	USBNWrite (FIFORXC0, RX_EN);
	USBNRead (RXD0);
	USBNRead (RXD0);

	//USBNWrite(FIFOTXC0,FLUSH);
	//USBNWrite(TXD0,0x24);
	//USBNWrite(TXD0,0x25);
#endif
}

void USBNDecodeClassRequest (DeviceRequest * req)
{
#if 0
	//SendHex(req->bRequest);       // decode request code
	SendHex (req->wLength);		// decode request code
	USBNWrite (FIFORXC0, RX_EN);
	USBNRead (RXD0);
	USBNRead (RXD0);
#endif
}

// ********************************************************************
// This subroutine handles the communication with usbn9604          
// ********************************************************************

// Read data from usbn96x register
// we use non-multiplexed mode

void USBNInitMC (void)
{
	// interrupt on INT4 pin falling edge (atmega128)
	//EICRB = (0 << ISC41) | (1 << ISC40);
	EICRB = (1 << ISC40);
	// interrupts on!
	EIMSK = (1 << INT4);					// allow extern irq4

	USB_CTRL_DDR  |= (1 << PF_A0) | (1 << PF_RD) | (1 << PF_WR);	// output (a0,rd,wr)
	USB_CTRL_PORT |= (1 << PF_RD) | (1 << PF_WR);
	USB_CS_DDR    |= (1 << PF_CS);
	USB_CS_PORT   |= (1 << PF_CS);

	sei ();
}

//////////////////////////////////////////////////////////////////////////////

static void USBNWriteAddr (uint8_t Adr)
{
	USB_DATA_OUT = Adr;				// put the address on the bus
	USB_DATA_DDR = 0xff;				// set for output
	
	// strobe the CS, WR, and A0 pins
	USB_CTRL_PORT |=  (1 << PF_A0);	// A0 = 1
	USB_CS_PORT   &= ~(1 << PF_CS);	// CS = 0
	USB_CTRL_PORT &= ~(1 << PF_WR);	// WR = 0
//	asm ("nop");						// pause for data to get to bus
	USB_CTRL_PORT |=  (1 << PF_WR);	// WR = 1 strobe end
	USB_CS_PORT   |=  (1 << PF_CS);	// CS = 1
	USB_CTRL_PORT &= ~(1 << PF_A0);	// A0 = 0
}

//////////////////////////////////////////////////////////////////////////////

static void USBNReadAddr (uint8_t Adr)
{
	USBNWriteAddr (Adr);
//	asm ("nop");				// pause for data to get to bus
	USB_DATA_DDR = 0x00;		// set PortD for input
}

void USBNReadBuf (uint8_t Adr, uint8_t len, uint8_t *buf)
{
	USBNReadAddr (Adr);
	
	USB_CS_PORT &= ~(1 << PF_CS);
	uint8_t ctrl1 = USB_CTRL_PORT;			// this is a little optimization
	uint8_t ctrl2 = ctrl1 & ~(1 << PF_RD);	// the G port is above 0x3F
	while (len--)
	{
		USB_CTRL_PORT = ctrl2;
		asm ("nop");						// pause for data to get to bus
		*buf++ = USB_DATA_IN;
		USB_CTRL_PORT = ctrl1;
	}
	USB_CS_PORT |= (1 << PF_CS);
}

uint8_t USBNRead (uint8_t Adr)
{
	USBNReadAddr (Adr);

	USB_CS_PORT   &= ~(1 << PF_CS);
	USB_CTRL_PORT &= ~(1 << PF_RD);
	asm ("nop");						// pause for data to get to bus
	uint8_t result = USB_DATA_IN;
	USB_CTRL_PORT |= (1 << PF_RD);
	USB_CS_PORT   |= (1 << PF_CS);
	return result;
}

//////////////////////////////////////////////////////////////////////////////

void USBNWriteBuf (uint8_t Adr, uint8_t len, const uint8_t *buf)
{
	USBNWriteAddr (Adr);
	
	USB_CS_PORT &= ~(1 << PF_CS);
	uint8_t ctrl1 = USB_CTRL_PORT;			// this is a little optimization
	uint8_t ctrl2 = ctrl1 & ~(1 << PF_WR);	// the G port is above 0x3F
	while (len--)
	{
		USB_DATA_OUT = *buf++;
		USB_CTRL_PORT = ctrl2;
		USB_CTRL_PORT = ctrl1;
	}
	USB_CS_PORT |=  (1 << PF_CS);
}

// Write data to usbn96x register
void USBNWrite (uint8_t Adr, uint8_t Data)
{
	USBNWriteAddr (Adr);
	
	USB_DATA_OUT = Data;				// put data on the bus
	USB_CS_PORT   &= ~(1 << PF_CS);
	USB_CTRL_PORT &= ~(1 << PF_WR);
	USB_CTRL_PORT |=  (1 << PF_WR);
	USB_CS_PORT   |=  (1 << PF_CS);
}

//////////////////////////////////////////////////////////////////////////////

void USBNDebug (const char *msg)
{
	UARTWrite (msg);
}

void USBNDebug_P (const char *msg)
{
	UARTWrite_P (msg);
}

void USBNDebugHex(uint8_t hex)
{
	SendHex (hex);
}
